package top.superflow.flow.validate

import top.superflow.exception.{Exceptable, RequestUnsupportedException}
import top.superflow.flow.config.process.ProcessConfig
import top.superflow.flow.config.{FlowConfig, ResourceConfig, RouteConfig}
import top.superflow.utils.ClassUtils

class ValidatorFactory private {

}

object ValidatorFactory extends Exceptable{
  val validators = Map[String, ConfigValidator[_]](
    classOf[FlowConfig].getName -> new FlowValidator,
    classOf[ProcessConfig].getName -> new ProcessValidator,
    classOf[Array[RouteConfig]].getName -> new RouteValidator,
    classOf[ResourceConfig].getName -> new ResourceValidator,
    )


  private def getConfiguredValidator(targetType : Class[_]) : ConfigValidator[_] = {
    if(validators.contains(targetType.getName)){
      validators.get(targetType.getName).get
    }else{
      //validator exists for the first argument generic type, no need to check others
      val validatorForFirstArgument = getValidatorAccordingToGenericArgument(targetType, 0)
      if(validatorForFirstArgument != null){
        return validatorForFirstArgument
      }

      //the second generic argument is the most we check
      val validatorForSecondArgument = getValidatorAccordingToGenericArgument(targetType, 1)
      if(validatorForSecondArgument != null){
        return validatorForSecondArgument
      }

      null
    }
  }

  private def getValidatorAccordingToGenericArgument(targetType : Class[_], index : Int) : ConfigValidator[_] = {
    val argumentGenericType = ClassUtils.getArgumentGenericType(targetType, index)
    if(argumentGenericType == null){
      return null
    }

    //validator exists for the first argument generic type, no need to check others
    val validator = validators.get(argumentGenericType.getName)
    if(validator == None){
      throwRequestUnsupportedException("There is no validator for {}",argumentGenericType.getName )
    }
    val validatorArgument = validator.get
    if(validatorArgument != null){
      return validatorArgument
    }

    null
  }

  def getValidator(flowElement: Any): ConfigValidator[_] = {
    if (flowElement == null) {
      throw new RequestUnsupportedException(flowElement)
    }

    val targetType = flowElement.getClass
    val configuredValidator : ConfigValidator[_] = getConfiguredValidator(targetType)

    if (configuredValidator == null) {
      throw new RequestUnsupportedException("There is no corresponding validator for the flow element {}", flowElement)
    } else {
      configuredValidator
    }
  }

}